#include "GRO_Gui.h"
#include "GRO_Backend_Sprig.h"
#include "GRO_Font_NFont.h"
#include <iostream>
#include "SDL_image.h"
#include <unistd.h>
using namespace std;
using namespace GRO;

SDL_Surface* screen;

class GameState
{
    public:
    enum StateEnum{TITLESCREEN, MENU, GAME, OPTIONS} currentState;
    
    int numRows;
    int numColumns;
    
    Uint32* colors;
    bool grayscale;
    
    Uint32 timer;
    int delay;
    
    int fadeDist;
    int colorDist;
    
    GameState()
        : currentState(TITLESCREEN)
        , numRows(10), numColumns(10)
        , colors(NULL)
        , grayscale(false)
        , timer(0)
        , delay(400)
        , fadeDist(130)
        , colorDist(130)
    {}
};

void changeState(GameState* state, GameState::StateEnum newState)
{
    if(state != NULL)
        state->currentState = newState;
}

void initState(GameState* state)
{
    if(state != NULL)
    {
        delete[] state->colors;
        state->colors = new Uint32[state->numRows * state->numColumns];
        memset(state->colors, 0, 4 * state->numRows * state->numColumns);
        state->timer = SDL_GetTicks();
    }
}

void quitFn()
{
    exit(0);
}

void setupGui(GameState* state)
{
    
    EnableUnicode();
    KeyRepeat();
    
    Gui& gui = Gui::instance();
    gui.init(screen->format, screen->w, screen->h);
    GRO_SetRenderer(new Renderer_Sprig(screen));
    
    NFont* blackfont1 = new NFont;
    blackfont1->load(screen, IMG_Load("BlackTahoma16.png"));
    
    NFont* whiteFont1 = new NFont;
    whiteFont1->load(screen, NFont::verticalGradient(blackfont1->getSurface(), 0xffffff, 0x999999, 0));
    
    GRO_Font* blackfont = new GRO_Font_NFont(blackfont1);
    GRO_Font* whiteFont = new GRO_Font_NFont(whiteFont1);
    
    // TITLESCREEN
    Panel* titlescreen = new Panel(0, 0, screen->w, screen->h);
    Button* titlescreenButton = new Button(screen->w, screen->h, new Text("GRO Gui Demo1\nClick to Begin", blackfont));
    titlescreen->xPadding = titlescreen->yPadding = 0;
    titlescreen->add(titlescreenButton);
    titlescreenButton->onClick.connect<Panel, void>(titlescreen, &Panel::close);
    
    gui.add(titlescreen);
    
    
    // MAIN MENU
    Panel* menu = new Panel;
    Text* menuText = new Text("GRO Gui!", blackfont);
    Separator* menuSeparator = new Separator;
    Button* startButton = new Button(screen->w/4, screen->h/8, new Text("Start", blackfont));
    Button* optionsButton = new Button(screen->w/4, screen->h/8, new Text("Options", blackfont));
    Button* creditsButton = new Button(screen->w/4, screen->h/8, new Text("Credits", blackfont));
    Button* quitButton = new Button(screen->w/4, screen->h/8, new Text("Quit", blackfont));
    menu->add(menuText);
    menu->add(menuSeparator);
    menu->add(startButton);
    menu->add(optionsButton);
    menu->add(creditsButton);
    menu->add(quitButton);
    menu->fitContents();
    menu->move(screen->w/2 - menu->area.w/2, screen->h/2 - menu->area.h/2);
    menu->close();
    titlescreenButton->onClick.connect<Panel, void>(menu, &Panel::open);
    
    menuSeparator->resize(menu->area.w - menu->xPadding*2, menuSeparator->area.h);
    
    startButton->onClick.connect<void, GameState*, GameState::StateEnum>(changeState, state, GameState::GAME);
    
    startButton->onClick.connect<void, GameState*>(initState, state);
    // Signal for quitting
    quitButton->onClick.connect<void>(quitFn);
    
    gui.add(menu);
    
    
    // START
    Panel* gamePanel = new Panel(0, 0, 1, 1);
    gamePanel->setFrame(NULL);
    gamePanel->xPadding = gamePanel->yPadding = 0;
    Button* backButton = new Button(screen->w/10, screen->h/10, new Text("Back...", blackfont));
    backButton->onClick.connect<Panel, void>(gamePanel, &Panel::close);
    backButton->onClick.connect<Panel, void>(menu, &Panel::open);
    
    backButton->onClick.connect<void, GameState*, GameState::StateEnum>(changeState, state, GameState::MENU);
    
    Slider* fadeSlider = new Slider(100, 20);
    fadeSlider->link(&(state->fadeDist));
    fadeSlider->min = 100;
    fadeSlider->max = 160;
    fadeSlider->setValue(130);
    
    Slider* colorSlider = new Slider(100, 20);
    colorSlider->link(&(state->colorDist));
    colorSlider->min = 100;
    colorSlider->max = 160;
    colorSlider->setValue(130);
    
    Slider* speedSlider = new Slider(100, 20);
    speedSlider->link(&(state->delay));
    speedSlider->min = 50;
    speedSlider->max = 800;
    speedSlider->setValue(400);
    
    gamePanel->add(backButton);
    gamePanel->add(fadeSlider);
    gamePanel->add(speedSlider);
    gamePanel->set(1, 1, colorSlider);
    
    gamePanel->fitContents();
    
    gamePanel->close();
    startButton->onClick.connect<Panel, void>(gamePanel, &Panel::open);
    startButton->onClick.connect<Panel, void>(menu, &Panel::close);
    
    gui.add(gamePanel);
    
    
    // OPTIONS
    Panel* optionsMenu = new Panel;
    optionsMenu->grabInput = true;
    Text* optionsText = new Text("Game Options", blackfont);
    Separator* optionsSeparator = new Separator;
    Button* optionsQuit = new Button(screen->w/6, screen->h/10, new Text("OK", blackfont));
    optionsQuit->onClick.connect<Panel, void>(optionsMenu, &Panel::close);
    
    Checkbox* grayscaleCheckbox = new Checkbox(20, 20);
    grayscaleCheckbox->link(&(state->grayscale));
    
    Text* rowsText = new Text("Rows:", blackfont);
    Slider* rowsSlider = new Slider(100, 20);
    rowsSlider->link(&(state->numRows));
    rowsSlider->min = 2;
    rowsSlider->max = 100;
    Text* rowsNumber = new Text("100", blackfont);
    rowsNumber->link(&(state->numRows));
    
    //Text* columnsText = new Text("Columns:", blackfont);
    //Spinner* columnsSpinner = new Spinner(30, 40, 10, 2, 100, 30, 20, DOWN);
    //columnsSpinner->link(&(state->numColumns));
    Text* columnsText = new Text("Columns:", blackfont);
    Slider* columnsSlider = new Slider(100, 20);
    columnsSlider->link(&(state->numColumns));
    columnsSlider->min = 2;
    columnsSlider->max = 100;
    Text* columnsNumber = new Text("100", blackfont);
    columnsNumber->link(&(state->numColumns));
    
    optionsMenu->add(optionsText);
    optionsMenu->add(optionsSeparator);
    
    optionsMenu->add(new Text("Use Grayscale", blackfont));
    optionsMenu->add(rowsText);
    optionsMenu->add(columnsText);
    optionsMenu->add(optionsQuit);
    optionsMenu->set(2, 1, grayscaleCheckbox);
    optionsMenu->set(3, 1, rowsSlider);
    optionsMenu->set(3, 2, rowsNumber);
    //optionsMenu->set(4, 1, columnsSpinner);
    optionsMenu->set(4, 1, columnsSlider);
    optionsMenu->set(4, 2, columnsNumber);
    optionsMenu->fitContents();
    optionsMenu->move(screen->w/2 - optionsMenu->area.w/2, screen->h/2 - optionsMenu->area.h/2);
    
    optionsSeparator->resize(optionsMenu->area.w - optionsMenu->xPadding*2, optionsSeparator->area.h);
    
    optionsMenu->close();
    optionsButton->onClick.connect<Panel, void>(optionsMenu, &Panel::open);
    gui.add(optionsMenu);
    
    // CREDITS
    Panel* credits = new Panel(screen->w/3, screen->h/3, screen->w/3, screen->h/3);
    credits->grabInput = true;
    Text* creditsText = new Text("GRO Gui Demo1\n by Jonathan Dearborn\n\n\n\n\n\nShowing off GRO Gui,\n also by Jonathan Dearborn\n\nSpecial thanks to my wife!", whiteFont);
    ScrollBar* creditsScroll = new ScrollBar(20, screen->h/3, 20, 40, 20, 20, DOWN);
    creditsScroll->setDock(DOCK_UP_RIGHT);
    Button* creditsQuit = new Button(screen->w/6, screen->h/10, new Text("Cool!", blackfont));
    creditsQuit->onClick.connect<Panel, void>(credits, &Panel::close);
    credits->add(creditsText);
    credits->add(creditsQuit);
    credits->pin(creditsScroll);
    credits->scrollY = creditsScroll;
    
    credits->close();
    creditsButton->onClick.connect<Panel, void>(credits, &Panel::open);
    gui.add(credits);
    credits->setBoxColor(SDL_MapRGB(screen->format, 0, 0, 0));
}

void start()
{
    GameState state;
    setupGui(&state);
    
    Uint32 frametime;
    
    float targetFps = 60;
    float waitTime = 1000.0f / targetFps;
    
    Gui& gui = Gui::instance();
    
    int mx = 0, my = 0;
    
    bool done = 0;
    SDL_Event event;
    int frameStart;
    while (!done)
    {
        frameStart = SDL_GetTicks();
        SDL_FillRect(screen, NULL, 0x7171C6);
        SDL_GetMouseState(&mx, &my);
        
        while (SDL_PollEvent(&event))
        {
            if (event.type == SDL_QUIT)
                done = 1;
            
            if(gui.event(event) != NULL)
                continue;
            

            if (event.type == SDL_KEYDOWN)
            {
                if (event.key.keysym.sym == SDLK_q)
                    done = 1;
            }
        }
        
        gui.update();
        
        switch(state.currentState)
        {
            case GameState::TITLESCREEN:
            case GameState::MENU:
            
            break;
            case GameState::GAME:
            if(SDL_GetTicks() - state.timer >= state.delay)
            {
                for(int r = 0; r < state.numRows; r++)
                {
                    for(int c = state.numColumns - 1; c > 0; c--)
                    {
                        Uint8 R, G, B;
                        SDL_GetRGB(state.colors[c - 1 + r*state.numColumns], screen->format, &R, &G, &B);
                        if(r < state.numRows/3)
                        {
                            G = int(G/(state.colorDist/100.0f));
                            B = int(B/(state.colorDist/100.0f));
                        }
                        else if(r < 2*state.numRows/3)
                        {
                            R = int(R/(state.colorDist/100.0f));
                            B = int(B/(state.colorDist/100.0f));
                        }
                        else
                        {
                            R = int(R/(state.colorDist/100.0f));
                            G = int(G/(state.colorDist/100.0f));
                        }
                        state.colors[c + r*state.numColumns] = SDL_MapRGB(screen->format, int(R/(state.fadeDist/100.0f)), int(G/(state.fadeDist/100.0f)), int(B/(state.fadeDist/100.0f)));
                    }
                    if(state.grayscale)
                    {
                        Uint8 gray = rand()%256;
                        state.colors[r*state.numColumns] = SDL_MapRGB(screen->format, gray, gray, gray);
                    }
                    else
                        state.colors[r*state.numColumns] = SDL_MapRGB(screen->format, rand()%256, rand()%256, rand()%256);
                }
                state.timer = SDL_GetTicks();
            }
            for(int r = 0; r < state.numRows; r++)
            {
                for(int c = 0; c < state.numColumns; c++)
                {
                    SDL_Rect rect = {c*screen->w/float(state.numColumns), r*screen->h/float(state.numRows),
                                    screen->w/float(state.numColumns), screen->h/float(state.numRows)};
                    SDL_FillRect(screen, &rect, state.colors[c + r*state.numColumns]);
                }
            }
            break;
        }
        
        gui.draw();
        
        
        SDL_Flip(screen);
        
        frametime = SDL_GetTicks() - frameStart;

        if (SDL_GetTicks() - frameStart < waitTime)
            SDL_Delay((int)(waitTime - frametime));

    }
    
    
}







int main(int argc, char* argv[])
{
    char buffer[2000];
    getcwd(buffer, 2000);
    
    string path = argv[0];
    path = path.substr(0, path.find_last_of('/'));
    path += '/';
    chdir(path.c_str());
    
    char buff[] = "SDL_VIDEO_CENTERED=center";
    
    SDL_putenv(buff);
    
    screen = SPG_InitSDL(800, 600, 32, SDL_INIT_VIDEO, SDL_SWSURFACE);
    if(screen == NULL)
        return 0;
    
    SDL_WM_SetCaption("GRO Gui Demo1", NULL);
    
    srand(time(NULL));
    start();
    
    SDL_Quit();
    return 0;
}
